<template>
  <el-form :model="formData" :rules="formRules" ref="formRef" :label-position="labelPosition" :label-width="labelWidth">
    <template v-for="(row, rowIndex) in formConfig" :key="rowIndex">
      <el-row :justify="row.justify || 'start'" :gutter="row.gutter || 20">
        <template v-for="(item, colIndex) in row.columns" :key="colIndex">
          <el-col v-if="!item.hidden" :span="item.span || 24">
            <el-form-item :label="item.label" :prop="item.prop">
              <!-- 输入框 -->
              <el-input v-if="item.type === 'input' && !item.showview" v-model="formData[item.prop]"
                :placeholder="item.placeholder" :type="item.inputType || 'text'" :disabled="item.disabled"
                :readonly="item.readonly" :clearable="item.clearable !== false" :show-password="item.showPassword" />
              <div v-if="item.showview"> {{ formData[item.prop] }}</div>
              <!-- 文本域 -->
              <el-input v-else-if="item.type === 'textarea' && !item.showview" v-model="formData[item.prop]"
                type="textarea" :placeholder="item.placeholder" :rows="item.rows || 3" :disabled="item.disabled"
                :readonly="item.readonly" show-word-limit :maxlength="item.maxlength" />
              <div v-if="item.showview"> {{ formData[item.prop] }}</div>
              <!-- 选择器 -->
              <el-select v-else-if="item.type === 'select'" v-model="formData[item.prop]"
                :placeholder="item.placeholder" :disabled="item.disabled" :clearable="item.clearable !== false"
                :multiple="item.multiple" popper-class="form-select" @change="(value) => handleSelectChange(item.prop, value)">
                <el-option v-for="option in item.options" :key="option.value" :label="option.label"
                  :value="option.value" :disabled="option.disabled" />
              </el-select>


              <!-- 时间选择器 -->
              <el-time-picker v-else-if="item.type === 'time'" v-model="formData[item.prop]"
                :placeholder="item.placeholder" :disabled="item.disabled" :clearable="item.clearable !== false"
                :format="item.format" :value-format="item.valueFormat" />


              <!-- 日期选择器 -->
              <el-date-picker v-else-if="item.type === 'date'" v-model="formData[item.prop]" :type="item.type || 'date'"
                :placeholder="item.placeholder" :disabled="item.disabled" :clearable="item.clearable !== false"
                :format="item.format" :value-format="item.valueFormat" />

              <!-- 日期时间选择器 -->
              <el-date-picker v-else-if="item.type === 'datetime'" v-model="formData[item.prop]"
                :type="item.type || 'datetime'" :placeholder="item.placeholder" :disabled="item.disabled"
                :clearable="item.clearable !== false" :format="item.format" :value-format="item.valueFormat" />

              <!-- 日期范围选择器 -->
              <el-date-picker v-else-if="item.type === 'daterange'" v-model="formData[item.prop]" type="daterange"
                :placeholder="item.placeholder" :disabled="item.disabled" :clearable="item.clearable !== false"
                :format="item.format" :value-format="item.valueFormat" :start-placeholder="item.startPlaceholder"
                :end-placeholder="item.endPlaceholder" />

              <!-- 日期时间范围选择器 -->
              <el-date-picker v-else-if="item.type === 'datetimerange'" v-model="formData[item.prop]"
                type="datetimerange" :placeholder="item.placeholder" :disabled="item.disabled"
                :clearable="item.clearable !== false" :format="item.format" :value-format="item.valueFormat"
                :start-placeholder="item.startPlaceholder" :end-placeholder="item.endPlaceholder" />

              <!-- 文件上传 -->
              <div v-else-if="item.type === 'upload'" class="upload-wrapper">
                <el-upload :ref="el => uploadRefs[item.prop] = el" class="upload-demo" :limit="item.limit || 1"
                  action="#" :accept="item.accept"
                  :on-change="(file, fileList) => handleUploadChange(item.prop, file, fileList)"
                  :on-exceed="(files, fileList) => handleUploadExceed(item.prop, files, fileList)"
                  :show-file-list="false" :auto-upload="false" :disabled="item.disabled" :multiple="false">
                  <template v-if="item.useInputSlot">
                    <el-input v-model="formData[item.prop]" :placeholder="item.placeholder" readonly
                      class="input-upload input-background" />
                  </template>
                  <template v-else>
                    <el-button size="small" type="primary">{{ item.buttonText || '点击上传' }}</el-button>
                  </template>
                </el-upload>
              </div>

              <!-- 自定义插槽 -->
              <slot v-else-if="item.type === 'slot'" :name="item.slotName" :form-data="formData" :item="item" />
            </el-form-item>
          </el-col>
        </template>
      </el-row>
    </template>
  </el-form>
</template>

<script setup>
/**
 * 动态表单组件
 * 支持多种表单元素类型，包括输入框、文本域、选择器、日期选择器、文件上传等
 * 可通过配置项动态生成表单，验证规则直接定义在配置中
 */
import { ref, reactive, onMounted, watch, computed } from 'vue'
import { genFileId } from 'element-plus'
// 定义组件属性
const props = defineProps({
  // 表单配置
  formConfig: {
    type: Array,
    default: () => []
  },
  // 表单数据
  modelValue: {
    type: Object,
    default: () => ({})
  },
  // 标签位置
  labelPosition: {
    type: String,
    default: 'top'
  },
  // 标签宽度
  labelWidth: {
    type: [String, Number],
    default: '100px'
  },
  // 是否显示操作按钮
  showActions: {
    type: Boolean,
    default: true
  },
  // 是否显示提交按钮
  showSubmitButton: {
    type: Boolean,
    default: true
  },
  // 是否显示取消按钮
  showCancelButton: {
    type: Boolean,
    default: true
  },
  // 提交按钮文本
  submitText: {
    type: String,
    default: '提交'
  },
  // 取消按钮文本
  cancelText: {
    type: String,
    default: '取消'
  },
  // 提交按钮加载状态
  submitLoading: {
    type: Boolean,
    default: false
  },
  // 取消按钮加载状态
  cancelLoading: {
    type: Boolean,
    default: false
  }
})

// 定义事件
const emit = defineEmits([
  'update:modelValue',
  'elsubmit',
  'cancel',
  'reset',
  'upload-change',
  'upload-exceed',
  'select-change'  // 添加选择器change事件
])

// 表单引用
const formRef = ref(null)

// 上传组件引用
const uploadRefs = ref({})

// 表单数据
const formData = reactive({ ...props.modelValue })

/**
 * 计算表单验证规则
 * 从 formConfig 中提取每个字段的验证规则
 */
const formRules = computed(() => {
  const rules = {}

  // 遍历表单配置，提取验证规则
  props.formConfig.forEach(row => {
    row.columns.forEach(item => {
      // 如果字段配置了验证规则，则添加到 rules 对象中
      if (item.rules && Array.isArray(item.rules) && item.rules.length > 0) {
        rules[item.prop] = item.rules
      }
    })
  })

  return rules
})

// 监听表单数据变化
watch(
  () => props.modelValue,
  (newVal) => {
    Object.keys(newVal).forEach(key => {
      formData[key] = newVal[key]
    })
  },
  { deep: true }
)

// 监听表单数据变化并触发更新事件
watch(
  formData,
  (newVal) => {
    emit('update:modelValue', { ...newVal })
  },
  { deep: true }
)

/**
 * 处理选择器变化事件
 * @param {String} prop - 表单字段名
 * @param {Any} value - 选择器的值
 */
const handleSelectChange = (prop, value) => {
  // 触发自定义事件
  emit('select-change', { prop, value })
}

/**
 * 处理文件上传变化事件
 * @param {String} prop - 表单字段名
 * @param {Object} file - 当前上传的文件
 * @param {Array} fileList - 文件列表
 */
const rollfile = ref({})

const handleUploadChange = (prop, file, fileList) => {
  // 更新表单数据
  if (fileList.length > 0) {
    formData[prop] = fileList[fileList.length - 1].name
    rollfile.value = file
  } else {
    formData[prop] = ''
  }

  // 触发自定义事件
  emit('upload-change', { prop, file, fileList })
}

/**
 * 处理文件上传超出限制事件
 * @param {String} prop - 表单字段名
 * @param {Array} files - 超出限制的文件列表
 * @param {Array} fileList - 当前文件列表
 */
const handleUploadExceed = (prop, files, fileList) => {

  uploadRefs.value[prop].clearFiles()
  const file = files[0]
  file.uid = genFileId()
  uploadRefs.value[prop].handleStart(file)


  emit('upload-exceed', { prop, files, fileList })
}

/**
 * 提交表单
 * 验证表单数据并通过 emit 触发 submit 事件
 */
const handleSubmit = async () => {
  if (!formRef.value) return

  try {
    await formRef.value.validate((valid) => {
      if (valid) {
        // 遍历表单配置，判断是否有文件类型的字段
        let hasFileField = false
        props.formConfig.forEach(row => {
          row.columns.forEach(item => {
            if (item.type === 'upload') {
              hasFileField = true
            }
          })
        })

        if (hasFileField) {
          emit('elsubmit', { ...formData, rollfile: rollfile.value })
        } else {
          emit('elsubmit', { ...formData })
        }
      }
    })
  } catch (error) {
    console.error('表单验证失败:', error)
  }
}

/**
 * 重置表单
 * 重置表单数据为初始值并通过 emit 触发 reset 事件
 */
const handleReset = () => {
  if (formRef.value) {
    formRef.value.resetFields()

    // 重置上传组件
    Object.keys(uploadRefs.value).forEach(key => {
      if (uploadRefs.value[key]) {
        uploadRefs.value[key].clearFiles()
      }
    })

    // 重置表单数据为初始值
    Object.keys(formData).forEach(key => {
      formData[key] = props.modelValue[key] || ''
    })

    emit('reset', { ...formData })
  }
}

/**
 * 取消操作
 * 通过 emit 触发 cancel 事件
 */
const handleCancel = () => {
  emit('cancel')
}

/**
 * 手动验证表单
 * @returns {Promise} 验证结果的 Promise
 */
const validate = () => {
  return formRef.value ? formRef.value.validate() : Promise.reject(false)
}

/**
 * 清除表单验证
 */
const clearValidate = () => {
  if (formRef.value) {
    formRef.value.clearValidate()
  }
}

/**
 * 重置特定字段的验证
 * @param {Array} props - 需要重置验证的字段数组
 */
const resetFields = (props = []) => {
  if (formRef.value) {
    formRef.value.resetFields(props)
  }
}

/**
 * 清除指定上传组件的文件列表
 * @param {String} prop - 表单字段名
 */
const clearUploadFiles = (prop) => {
  if (uploadRefs.value[prop]) {
    uploadRefs.value[prop].clearFiles()
  }
}

/**
 * 获取指定上传组件的文件列表
 * @param {String} prop - 表单字段名
 * @returns {Array} 文件列表
 */
const getUploadFiles = (prop) => {
  if (uploadRefs.value[prop]) {
    return uploadRefs.value[prop].uploadFiles || []
  }
  return []
}

/**
 * 手动上传文件
 * @param {String} prop - 表单字段名
 */
const submitUpload = (prop) => {
  if (uploadRefs.value[prop]) {
    uploadRefs.value[prop].submit()
  }
}

// 暴露方法给父组件
defineExpose({
  validate,
  clearValidate,
  resetFields,
  handleReset,
  clearUploadFiles,
  getUploadFiles,
  submitUpload,
  handleSubmit
})

onMounted(() => {
  // 组件挂载时的初始化操作
})
</script>

<style lang="less" scoped>
.form-actions {
  margin-top: 20px;

  :deep(.el-button) {
    margin-left: 10px;
  }
}

.upload-wrapper {
  width: 100%;

  .upload-demo {
    position: relative;
    display: inline-block;
    width: 100%;
  }

  :deep(.el-upload) {
    width: 100%;
  }

  :deep(.el-upload-list .el-upload) {
    background-color: #11375B;
  }

  .input-upload {
    width: 100%;
  }

  :deep(.input-background .el-input__wrapper) {
    background-color: #11375B;
  }

  :deep(.input-background .el-select__wrapper) {
    background-color: #11375B;
    box-shadow: none;
  }

  :deep(.input-background .el-select__wrapper .el-select__selected-item.el-select__placeholder) {
    color: #fff;
  }

  :deep(.input-background .el-input__wrapper .el-input__inner) {
    color: #fff;
  }

  :deep(.input-background .el-textarea__inner) {
    background-color: #11375B;
    color: #fff;
  }
}

:deep(.el-range-editor) {
  background: #11375b !important;
  box-shadow: #1d6db7 0px 0px 0px 0.815104px inset !important;

}

:deep(.el-date-editor .el-range-input) {
  color: #cbe7ff !important;
}
</style>